package org.zizi.manager;

import java.util.List;

import javax.sql.DataSource;

import org.zizi.action.ActionContext;
import org.zizi.action.UserException;
import org.zizi.dao.InlandRevenueOrgDao;
import org.zizi.dao.UserInfoDao;
import org.zizi.dao.VatCreditDao;
import org.zizi.dao.VatTypeDao;
import org.zizi.db.EasySql;
import org.zizi.db.build.DataSourceBuilder;
import org.zizi.db.build.EasySqlBuilder;
import org.zizi.db.build.EasySqlConfig;
import org.zizi.manager.impl.DaoManager;
import org.zizi.modal.SepInvoiceMoneyDetail;
import org.zizi.modal.User;
import org.zizi.modal.UserInfo;
import org.zizi.modal.VatCredit;
import org.zizi.modal.VatCreditInvoice;
import org.zizi.modal.VatType;
import org.zizi.util.NumberFormat;
import org.zizi.util.Options;

public class VatCreditManager implements Manager
{
	//数据连接配置
	private static final String DATABASE_TYPE = "VatCreditConfirmDatabaseType";
	private static final String DATABASE_SERVER = "VatCreditConfirmDatabaseServer";
	private static final String DATABASE_PORT = "VatCreditConfirmDatabasePort";
	private static final String DATABASE_NAME = "VatCreditConfirmDatabaseName";
	private static final String DATABASE_USER = "VatCreditConfirmDatabaseUser";
	private static final String DATABASE_PASSWORD = "VatCreditConfirmDatabasePassword";
	private static final String DATABASE_MAX_CONNECTIONS = "VatCreditConfirmDatabaseMaxConnections";
	//数据查询SQL
	private static final String DATA_CONFIRM_SQL = "VatCreditConfirmSql";
	//附加错误消息
	private static final String ADDITIONAL_ERROR_MSG = "AdditionalErrorMessage";
	
	private static final int TRANSACTION_READ_COMMITTED = 2;
	
	private EasySqlConfig config;
	private EasySql esql;
	private DataSource source;
	private String sql;
	
	private VatTypeDao tDao;
	private UserInfoDao uiDao;
	private VatCreditDao vcDao;
	private InlandRevenueOrgDao iroDao;
	
	private String additionalErrorMessage;
	
	public void initialize(Options options) throws Exception
	{
		sql = options.get(DATA_CONFIRM_SQL, String.class);
		
		String type = options.get(DATABASE_TYPE, String.class);
		String server = options.get(DATABASE_SERVER, String.class);
		Integer port = options.get(DATABASE_PORT, Integer.class);
		String name = options.get(DATABASE_NAME, String.class);
		String user = options.get(DATABASE_USER, String.class);
		String password = options.get(DATABASE_PASSWORD, String.class);
		Integer connections = options.get(DATABASE_MAX_CONNECTIONS, Integer.class, null);
		
		additionalErrorMessage = options.get(ADDITIONAL_ERROR_MSG, String.class, null);
		
		config = new EasySqlConfig();
		config.setDatabase(type);
		config.setServer(server);
		config.setPort(port);
		config.setName(name);
		config.setUser(user);
		config.setPassword(password);
		config.setMax(connections);
		
		esql = EasySqlBuilder.build(type);
		source = DataSourceBuilder.build(config);
		
		tDao = Managers.get(DaoManager.class).getDao(VatTypeDao.class);
		uiDao = Managers.get(DaoManager.class).getDao(UserInfoDao.class);
		vcDao = Managers.get(DaoManager.class).getDao(VatCreditDao.class);
		iroDao = Managers.get(DaoManager.class).getDao(InlandRevenueOrgDao.class);
	}

	public void destory()
	{
	}
	
	public void check(VatCredit credit, boolean checkPrivilege) throws Exception
	{
		LoginManager lm = Managers.get(LoginManager.class);
		
		//基本数据检查
		if (credit.getIdentify() == null)
			throw formatException("请填写纳税人识别号！");
		if (credit.getYear() <= 0 || credit.getMonth() <= 0)
			throw formatException("请选择所属期！");
		if (credit.getApplyVatCredit() == null)
			throw formatException("请填写本期申报抵减税额！");
		
		//检查纳税人识别号
		UserInfo ui = uiDao.getUserInfo(credit.getIdentify());
		if (ui == null) throw formatException("您输入的纳税人识别号不正确，无法找到此纳税人相关信息。");
		
		//权限检查
		if (checkPrivilege)
		{
			User u = null;
			if (ActionContext.get() != null && ActionContext.get().getSession() != null) u = lm.getUser(ActionContext.get().getSession().getId());
			if (u != null)
			{
				List<String> codes = iroDao.getManagingInlandRevenueOrgCode(u.getOrgCode());
				if (codes == null || !codes.contains(ui.getOrgCode())) throw formatException("您没有权限录入此纳税人的抵减信息。");
			}
			else
			{
				throw formatException("请先登陆！");
			}
		}
		
		//时间检查
		boolean exist = vcDao.existLatterCredit(credit.getIdentify(), credit.getYear(), credit.getMonth(), credit.getId());
		if (exist) throw formatException("所属期错误：存在比当前所属期更晚或和当前所属期相同时间的抵减清单。");
		
		//检查是否存在错误的空值
		checkValueNotNull(credit.getInvoices());
		
		//检查内部是否有重复
		checkValueNotRepeat(credit.getInvoices());
		
		//检查是否和数据库中的值重复
		double thisAllowCredit = 0;
		for (VatCreditInvoice inv : credit.getInvoices())
		{
			//检查type_id是否正确
			VatType type = tDao.getVatType(inv.getInvoiceTypeId());
			if (type == null) throw formatException("无法找到项目内容：id=" + inv.getInvoiceTypeId());
			
			VatCreditInvoice t = vcDao.getVatCreditInvoiceByCodeAndNum(inv.getInvoiceCode(), inv.getInvoiceNum(), credit.getId());
			if (t != null) throw formatException("发票（代码=" + inv.getInvoiceCode() + "，号码=" + inv.getInvoiceNum() + "）已被使用，无法再次抵减。");
			
			if (inv.isSepInvoice())
			{
				VatCreditInvoice x = vcDao.getSepVatCreditInvoice(ui.getIdentify(), inv.getInvoiceTypeId(), credit.getId());
				if (x != null) throw formatException("此纳税人已提交过“" + type.getName() + "”的增值税专用发票！");
			
				//检查限额
				if (type.getSepMaxMoney() != null && inv.getInvoiceMoney() > type.getSepMaxMoney())
					throw formatException("项目内容为“" + type.getName() + "”的增值税专用发票超过限额（" + type.getSepMaxMoney() + "）！");
				
				//thisAllowCredit += inv.getInvoiceMoney() / 1.17;
				double money = checkSepInvoiceMoney(credit.getIdentify(), inv.getInvoiceCode(), inv.getInvoiceNum(), inv.getInvoiceMoney());
				thisAllowCredit += money;
			}
			else if (inv.isNorInvoice())
			{
				VatCreditInvoice x = vcDao.getManOrFixVatCreditInvoice(ui.getIdentify(), inv.getInvoiceTypeId(), credit.getYear(), credit.getId());
				if (x != null) throw formatException("此纳税人已提交过" + credit.getYear() + "年“" + type.getName() + "”的通用手工发票或定额发票！");
			
				//检查限额
				if (type.getNorMaxMoney() != null && inv.getInvoiceMoney() > type.getNorMaxMoney())
					throw formatException("项目内容为“" + type.getName() + "”的普通发票超过限额（" + type.getNorMaxMoney() + "）！");
				
				thisAllowCredit += inv.getInvoiceMoney();
			}
			else
			{
				thisAllowCredit += inv.getInvoiceMoney();
			}
		}
		
		//检查数据正确性
		double preLeftCredit = vcDao.getPreviousLeftCredit(credit.getIdentify(), credit.getYear(), credit.getMonth());
		double totalAllowCredit = preLeftCredit + thisAllowCredit;
		if (credit.getApplyVatCredit() < 0) throw formatException("本期申报抵减税额(" + NumberFormat.format(credit.getApplyVatCredit()) + ")小于0。");
		if (totalAllowCredit < credit.getApplyVatCredit()) throw formatException("本期申报抵减税额(" + NumberFormat.format(credit.getApplyVatCredit()) + ")超过可抵减税额(" + NumberFormat.format(totalAllowCredit) + ")。");
		
		credit.setThisLeftCredit(NumberFormat.format(totalAllowCredit - credit.getApplyVatCredit()));	//设置本期未抵减税额
	}
	
	//列表内部的发票号码和发票代码不能重复
	private void checkValueNotRepeat(List<VatCreditInvoice> invoices) throws UserException
	{
		for (int i = 0; i < invoices.size(); i++)
		{
			VatCreditInvoice x = invoices.get(i);
			
			for (int j = i + 1; j < invoices.size(); j++)
			{
				VatCreditInvoice y = invoices.get(j);
				
				//检查发票的项目内容是否重复
				
				//都是专用发票时或普通发票时
				if ((x.isSepInvoice() && y.isSepInvoice())
					|| (x.isNorInvoice() && y.isNorInvoice()))
				{
					if (x.getInvoiceTypeId().equals(y.getInvoiceTypeId()))
						throw formatException("专用发票或普通发票组中存在重复的项目内容，请编辑后重新提交！");
				}
				
				//若都不是其它类型发票，则检查号码和代码组是否存在重复
				if (!x.isOthInvoice() && !y.isOthInvoice())
				{
					if (x.getInvoiceCode().equals(y.getInvoiceCode()) 
						&& x.getInvoiceNum().equals(y.getInvoiceNum()))
						throw formatException("发票号码“" + x.getInvoiceCode() + "”和代码“" + x.getInvoiceNum() + "”的组合存在重复，请编辑后重新提交！");
				}
			}
		}
	}
	
	//检查发票值填写
	private void checkValueNotNull(List<VatCreditInvoice> invoices) throws UserException
	{
		for (VatCreditInvoice invoice : invoices)
		{
			if (invoice.isOthInvoice())	//其它类发票只检查金额和时间填写是否正确
			{
				if (invoice.getInvoiceMoney() == null || invoice.getInvoiceMoney() < 0) throw formatException("请填写正确的价税合计金额。");
				if (invoice.getInvoiceDate() == null) throw formatException("请填写正确的发票日期");
			}
			else
			{
				if (invoice.getInvoiceCode() == null || invoice.getInvoiceCode().trim().isEmpty()) throw formatException("请填写正确的发票代码。");
				if (invoice.getInvoiceNum() == null || invoice.getInvoiceNum().trim().isEmpty()) throw formatException("请填写正确的发票号码。");
				if (invoice.getInvoiceMoney() == null || invoice.getInvoiceMoney() < 0) throw formatException("请填写正确的价税合计金额。");
				if (invoice.getInvoiceDate() == null) throw formatException("请填写正确的发票日期");
			}
		}
	}
	
	//
	private double checkSepInvoiceMoney(String identify, String code, String number, Double money) throws UserException
	{
		try
		{
			esql.begin(TRANSACTION_READ_COMMITTED, source);
			
			SepInvoiceMoneyDetail d = esql.query(SepInvoiceMoneyDetail.class, sql, code, number, identify);
			if (d == null) throw formatException("增值税专用发票数据有误：未认证或不可用。");
			
			if ((d.getPrice() + d.getVat()) != money) throw formatException("增值税专用发票数据有误：金额填写错误。");
			
			esql.commit();
			
			return money;// d.getPrice();
		}
		catch (UserException e)
		{
			throw e;
		}
		catch (Exception e)
		{
			throw formatException("比较增值税专用发票数据错误：" + e.getMessage());
		}
		finally
		{
			esql.end();
		}
	}
	
	//
	private UserException formatException(String s)
	{
		String ex = s;
		if (additionalErrorMessage != null) ex += additionalErrorMessage;
		
		return new UserException(ex);
	}
}
